#!/usr/bin/python
# -*- coding:utf-8 -*-
from datetime import datetime

from flask_login import UserMixin
from flask_sqlalchemy import declared_attr
from werkzeug.security import generate_password_hash, check_password_hash

from app import db, login_manager
from app.database import enums


class BaseModel(db.Model):
    """
    数据模型基础类
    """
    __abstract__ = True

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)  # 主键
    create_on = db.Column(db.DateTime, default=datetime.now)  # 创建时间
    update_on = db.Column(db.DateTime, default=datetime.now)  # 更新时间
    delete_on = db.Column(db.DateTime)  # 删除时间
    is_active = db.Column(db.Boolean, default=True)  # 是否有效

    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    def save(self):
        """
        简单封装保存
        :return:
        """
        self.update_on = datetime.now()
        db.session.add(self)
        db.session.commit()

    def delete(self):
        """
        简单封装逻辑删除
        :return:
        """
        self.delete_on = datetime.now()
        self.is_active = False
        db.session.add(self)
        db.session.commit()


class Menu(BaseModel):
    """
    菜单模型
    """
    title = db.Column(db.String(32), nullable=False)  # 菜单名称
    position = db.Column(db.Integer, default=0, nullable=False)  # 菜单排序
    code = db.Column(db.String(32), nullable=False)  # 菜单编号
    link_url = db.Column(db.String(128), nullable=False)  # 菜单链接
    is_admin = db.Column(db.Boolean, default=False)  # 是否管理员菜单
    icon_class = db.Column(db.String(128))  # 图标class
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)  # 默认都是博主ID


class Role(BaseModel):
    """
    角色
    """
    name = db.Column(db.String(32), nullable=True)  # 角色名称
    users = db.relationship('User', backref='role')  # 用户


class User(UserMixin, BaseModel):
    """
    用户模型
    """
    # 验证信息
    account = db.Column(db.String(128), nullable=False, unique=True)  # 账号
    mobile = db.Column(db.String(128))  # 手机号
    mail = db.Column(db.String(128))  # 邮箱
    password_hash = db.Column(db.String(128), nullable=False)  # 加密密码

    # 个人信息
    nickname = db.Column(db.String(24), nullable=True)  # 昵称
    sex = db.Column(db.Integer, default=enums.OTHER_SEX)  # 性别
    introduction_one_word = db.Column(db.String(128))  # 一句话介绍
    introduction_detail = db.Column(db.Text)  # 详细简介
    github = db.Column(db.String(128))  # github地址

    # 关联信息
    avatar_id = db.Column(db.Integer, db.ForeignKey('attachment.id'))  # 头像ID
    role_id = db.Column(db.Integer, db.ForeignKey('role.id'))  # 角色ID
    blogs = db.relationship('Blog', backref='user', lazy='dynamic')  # 文章
    comments = db.relationship('Comment', backref='user', lazy='dynamic')  # 评论
    bloglikes = db.relationship('BlogLikes', backref='user', lazy='dynamic')  # 点赞数
    # 用户拥有菜单列表，默认博客暂用一对多。TODO:后期优化成多对多
    menus = db.relationship('Menu', backref='user', lazy='dynamic')

    @property
    def password(self):
        raise AttributeError('不能直接读取密码！')

    @password.setter
    def password(self, pwd):
        self.password_hash = generate_password_hash(pwd)

    def verify_password(self, pwd):
        return check_password_hash(self.password_hash, pwd)


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))


class Project(BaseModel):
    """
    项目经历
    """
    # 基础信息
    title = db.Column(db.String(128), nullable=True, unique=True)  # 项目名称
    project_url = db.Column(db.String(128))  # 在线地址
    skills = db.Column(db.String(128))  # 涉及技术
    about_project = db.Column(db.Text)  # 项目介绍

    # 关联信息
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)
    preview_img_id = db.Column(db.Integer, db.ForeignKey('attachment.id'))


# 博客标签多对多关系表
blog_tag_relation = db.Table('blog_tag_relation',
                             db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), nullable=False),
                             db.Column('blog_id', db.Integer, db.ForeignKey('blog.id'), nullable=False),
                             )


class Blog(BaseModel):
    """
    博文模型
    """
    # 基础信息
    title = db.Column(db.String(128), nullable=False)  # 文章标题
    description = db.Column(db.Text, nullable=False)  # 文章简介
    content = db.Column(db.Text, nullable=False)  # html格式
    md_content = db.Column(db.Text, nullable=False)  # markdown格式
    status = db.Column(db.Integer, nullable=False)  # 文章状态
    publish_time = db.Column(db.DateTime)  # 发布时间
    url_suffix = db.Column(db.String(128), nullable=False, unique=True)  # 地址后缀

    # 关联信息
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))  # 作者ID
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False)  # 文章分类， 一对多
    comments = db.relationship('Comment', backref='blog', lazy='dynamic')  # 评论
    blogviews = db.relationship('BlogViews', backref='blog', lazy='dynamic')  # 阅读量
    bloglikes = db.relationship('BlogLikes', backref='blog', lazy='dynamic')  # 喜欢数
    tags = db.relationship('Tag', secondary=blog_tag_relation, backref=db.backref('blogs', lazy='dynamic'))  # 文章标签，多对多关系


class BlogViews(BaseModel):
    """
    博文阅读量模型
    """
    blog_id = db.Column(db.Integer, db.ForeignKey('blog.id'), nullable=False)  # 博文ID
    ip_address = db.Column(db.String(128), nullable=False)  # IP地址


class BlogLikes(BaseModel):
    """
    博文喜欢量模型
    """
    blog_id = db.Column(db.Integer, db.ForeignKey('blog.id'), nullable=False)  # 博文ID
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)  # 用户ID


class Comment(BaseModel):
    """
    留言模型
    """
    # 基本信息
    content = db.Column(db.Text, nullable=True)  # 内容
    kind = db.Column(db.Integer, default=enums.OTHER_COMMENT)  # 留言类型

    # 关联信息
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)  # 留言人ID
    blog_id = db.Column(db.Integer, db.ForeignKey('blog.id'), nullable=False)  # 文章ID


class Category(BaseModel):
    """
    文章分类
    """
    name = db.Column(db.String(32), nullable=False)  # 分类名称
    blogs = db.relationship('Blog', backref='category', lazy='dynamic')  # 文章


class Tag(BaseModel):
    """
    博客标签
    """
    name = db.Column(db.String(32), nullable=True)  # 标签名称


class Attachment(BaseModel):
    """
    附件模型
    """
    # 基本信息
    file_name = db.Column(db.String(128), nullable=False)  # 原始文件名
    file_key = db.Column(db.String(128), nullable=False)  # 云存储KEY
    file_kind = db.Column(db.Integer, default=enums.OTHER_FILE)  # 文件类型
    attachment_kind = db.Column(db.Integer, default=enums.OTHER_ATTACHMENT)  # 附件分类



